// src/crudOption/channel/miniProgramAction.js

/**
 * 小程序审核状态操作按钮配置
 *
 * 业务状态：
 * - NONE: 未提交审核
 * - PROCESS: 提审中
 * - SUCCESS: 提审通过
 * - FAIL: 提审失败
 *
 * 用法（页面 setup）：
 *
 *   import { createBuildMiniProgramActions } from '@/crudOption/channel/miniProgramAction'
 *
 *   const buildRowActions = createBuildMiniProgramActions({
 *     fns: {
 *       confirmFirstSubmit,
 *       confirmResubmit,
 *       confirmSubmit,
 *       confirmRollback,
 *       openReasonDialog,
 *       openLogDialog
 *     },
 *     denyStrategy: 'hide',  // 或 'disable'：未授权时显示但禁用
 *   })
 *
 *   // 模板：
 *   // <ActionBar :row="row" :max-inline="3" :actions="buildRowActions" />
 */

// ===== 业务状态判断 =====
const U = v => (v == null ? "" : String(v).toUpperCase());

function auditStatusOf(row) {
  // 后端：auditStatus ∈ { NONE, PROCESS, SUCCESS, FAIL }
  return U(row.auditStatus || row.status);
}

const isNone = row => auditStatusOf(row) === "NONE" || !auditStatusOf(row); // 未提交审核
const isProcess = row => auditStatusOf(row) === "PROCESS"; // 提审中
const isSuccess = row => auditStatusOf(row) === "SUCCESS"; // 提审通过
const isFail = row => auditStatusOf(row) === "FAIL"; // 提审失败

// 可操作条件
const isCancelled = row => row.authStatus === "CANCEL"; // 已取消状态判断

const canFirstSubmit = row => !isCancelled(row) && isNone(row); // 未取消且未提交审核 -> 首次提审
const canResubmit = row => !isCancelled(row) && (isProcess(row) || isFail(row)); // 未取消且提审中或提审失败 -> 重新提审
const canSubmit = row => !isCancelled(row) && isSuccess(row); // 未取消且提审通过 -> 提审
const canRollback = row => !isCancelled(row) && (isProcess(row) || isSuccess(row) || isFail(row)); // 未取消且提审中、通过、失败都可以回滚
const canViewReason = row => !isCancelled(row) && isFail(row); // 未取消且只有提审失败才能查看失败原因
const canViewLog = row => !isCancelled(row); // 未取消状态都可以查看日志
const canContactCustomer = row => isCancelled(row); // 已取消状态 -> 联系客户

// ===== 只用 hasAuth 做校验 =====
/**
 * @param {Function} hasAuth  (keys:string[]) => boolean
 * @param {string|string[]|function|undefined|null} perm
 * @param {object} row
 */
function allowByPerm(hasAuth, perm, row) {
  // 没配置权限点 => 不受权限控制，直接放行
  if (!perm) return true;

  // 自定义函数（少数特殊场景）
  if (typeof perm === "function") {
    try {
      return !!perm(row);
    } catch {
      return false;
    }
  }

  // 字符串或数组 => 调用 hasAuth（任一命中即通过）
  const keys = Array.isArray(perm) ? perm : [perm];
  return typeof hasAuth === "function" ? !!hasAuth(keys) : false;
}

/**
 * 未授权处理：'hide'（默认）| 'disable'
 */
function applyDenyStrategy(action, denyStrategy) {
  if (denyStrategy === "disable") {
    return { ...action, disabled: true, onClick: undefined, danger: false, divided: false };
  }
  return null; // hide
}

// 核心：解析 hasAuth（支持注入；没传则尝试从 Pinia 获取）
function resolveHasAuth(passedHasAuth) {
  if (passedHasAuth) return passedHasAuth;
  try {
    const user = useUserInfoStore(); // ⚠️ 必须在 setup() 或激活的 Pinia 上下文里调用
    return user.hasAuth; // getters 返回的就是 (keys)=>boolean
  } catch {
    console.warn("[miniProgramAction] hasAuth 未传且 Pinia 未激活，默认视为无权限");
    return () => false;
  }
}

/**
 * 工厂：生成 (row)=>actions
 * @param {object} opts
 *  - hasAuth: (keys:string[])=>boolean       // 非必传：Pinia 的 hasAuth
 *  - fns: {
 *     confirmFirstSubmit,  // 首次提审确认
 *     confirmResubmit,     // 重新提审确认
 *     confirmSubmit,       // 提审确认
 *     confirmRollback,     // 回滚确认
 *     openReasonDialog,    // 打开失败原因弹窗
 *     openLogDialog,       // 打开日志弹窗
 *     contactCustomer      // 联系客户
 *   }
 *  - denyStrategy?: 'hide'|'disable'         // 默认 'hide'
 */
export function createBuildMiniProgramActions(opts = {}) {
  const hasAuth = resolveHasAuth(opts.hasAuth);
  const fns = opts.fns || {};
  const denyStrategy = opts.denyStrategy === "disable" ? "disable" : "hide";

  return function buildRowActions(row) {
    // 候选按钮：
    // 说明：perm 缺省 => 无权限限制；若需要受控，填入权限点字符串或数组
    const candidates = [
      {
        key: "firstSubmit",
        label: "首次提审",
        order: 1,
        when: canFirstSubmit(row),
        type: "primary",
        // perm: "mini.firstSubmit",
        onClick: () => fns.confirmFirstSubmit?.(row),
      },
      {
        key: "resubmit",
        label: "重新提审",
        order: 2,
        when: canResubmit(row),
        type: "primary",
        // perm: "mini.resubmit",
        onClick: () => fns.confirmResubmit?.(row),
      },
      {
        key: "submit",
        label: "提审",
        order: 3,
        when: canSubmit(row),
        type: "primary",
        // perm: "mini.submit",
        onClick: () => fns.confirmSubmit?.(row),
      },
      {
        key: "rollback",
        label: "回滚",
        order: 4,
        when: canRollback(row),
        type: "primary",
        // perm: "mini.rollback",
        onClick: () => fns.confirmRollback?.(row),
      },
      {
        key: "reason",
        label: "失败原因",
        order: 5,
        when: canViewReason(row),
        type: "primary",
        // perm: "mini.reason",
        onClick: () => fns.openReasonDialog?.(row),
      },
      {
        key: "log",
        label: "日志",
        order: 6,
        when: canViewLog(row),
        type: "primary",
        // perm: "mini.log",
        onClick: () => fns.openLogDialog?.(row),
      },
      {
        key: "contactCustomer",
        label: "联系客户",
        order: 7,
        when: canContactCustomer(row),
        type: "primary",
        // perm: "mini.contactCustomer",
        onClick: () => fns.contactCustomer?.(row),
      },
    ];

    const seen = new Set();
    const result = [];

    for (const a of candidates) {
      if (!a || !a.when) continue;

      const pass = allowByPerm(hasAuth, a.perm, row);
      const finalAction = pass ? a : applyDenyStrategy(a, denyStrategy);

      if (!finalAction) continue;
      if (seen.has(finalAction.key)) continue;
      seen.add(finalAction.key);
      result.push(finalAction);
    }

    result.sort((x, y) => (x.order ?? 0) - (y.order ?? 0));
    return result;
  };
}

/**
 * 一次性生成（可选导出）
 * @param {object} row
 * @param {object} options { hasAuth, fns, denyStrategy }
 */
export function buildMiniProgramActions(row, options = {}) {
  return createBuildMiniProgramActions(options)(row);
}

export default createBuildMiniProgramActions;
